package com.sebscape.sebcms.tools;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.tools.generic.*;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * User: Steve
 * Date: Jul 16, 2004
 * Time: 7:13:57 AM
 */

/**
 * VelocityTools
 **/
public class VelocityTools
{
    private static Log log = LogFactory.getLog(VelocityTools.class);
    private static final String LOGGER_NAME="CON";
    private final VelocityEngine ve;
    
    ////////////////////////////////////////////////////////
    // Constructors
    ////////////////////////////////////////////////////////

    /**
     *  Default Constructor
     **/
    public VelocityTools()
    {
    	ve = new VelocityEngine();
    	// tell velocity to use the existing Log4J system.
    	try {
			ve.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
				"org.apache.velocity.runtime.log.Log4JLogChute" );
			ve.setProperty( "runtime.log.logsystem.log4j.logger",
			              LOGGER_NAME );
			ve.init();
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    /**
     * Passed a Path to a File using Velocity tags, and a map of variables and values, this method
     * will produce the resulting, merged String.
     * @param templateLocalPathAndFile
     * @param valueMap
     * @return
     */
    public static String velocityParagraph( String templateLocalPathAndFile, Map<String,Object> valueMap ){
        // create a new instance of the engine
        VelocityEngine ve = new VelocityEngine();
        // extract the directory under which the file is located from templatePath
        File file = new File(templateLocalPathAndFile);
        String path = file.getParentFile().getPath();
        log.debug("Path is: "+path);
        log.debug("Filename is: "+file.getName());
        ve.setProperty( VelocityEngine.FILE_RESOURCE_LOADER_PATH, path );
        //initialize the engine
        try
        {
            ve.init();
        }
        catch (Exception e)
        {
            log.error(e.getMessage());
            e.printStackTrace();
        }

        //Load the context values...
        VelocityContext context = new VelocityContext();
        Iterator<String> valsIter = valueMap.keySet().iterator();
        while (valsIter.hasNext()) {
            String key = (String)valsIter.next();
            context.put( key, valueMap.get(key) );
            log.debug("added: ( "+ key + ", " + valueMap.get(key) +" )" );
        }
        //Load velocityTools
        context.put("dateTool", new DateTool());
        context.put("renderTool", new RenderTool());
        context.put("iteratorTool", new IteratorTool());
        context.put("numberTool", new NumberTool());
        context.put("mathTool", new MathTool());

        // Load the template
        Template template = null;
        try
        {
            template = ve.getTemplate(file.getName());
        }
        catch (Exception e)
        {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        // have Velocity compile the page
        StringWriter sw = new StringWriter();
        String paragraph = null;
        try
        {
            template.merge( context, sw );
            paragraph = sw.toString();
        }
        catch (Exception e)
        {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        //return the results
        log.debug("generated paragraph: "+paragraph);
        return paragraph;
    }

    public static void main(String[] args)
    {
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("key1", "This is value1");
        map.put("key2", "This is value2");
        // System.out.println("return:\n"+ velocityParagraph("//c:/temp/velocityTest.vtl", map));
        try {
        	VelocityTools vt = new VelocityTools();
			System.out.println( "returns: " + vt.merge("key1=$key1 and key2=$key2", map, "Email Merge" ) );
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    /**
     * Merges a velocity message body, given a template in the classpath.
     *
     * @param engine
     * @param template
     * @param valueMap
     * @return
     */
    public String merge(String template, Map valueMap) {
        // create a context
    	VelocityContext context = new VelocityContext( valueMap );
    	// var to collect the merged string.
    	StringWriter writer = new StringWriter();
        String body;
        try {
            ve.mergeTemplate(template, Velocity.ENCODING_DEFAULT, context, writer);
            String messageBody = writer.toString();
            body = messageBody;
        } catch (Exception e) {
            throw new RuntimeException("Couldn't process Velocity template with name='" + template + "'.", e);
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (Exception e) {
                log.error("Failed to close StringWriter", e);
            }
        }
        return body;
    }
    
    public String merge(String template, Map<String,Object> valueMap, String tagForLogMessages) 
    	throws ParseErrorException, MethodInvocationException, ResourceNotFoundException, IOException {
    	log.debug( "using template: " + template );
    	StringReader reader = new StringReader( template );
    	StringWriter output = new StringWriter();
    	VelocityContext context = new VelocityContext( valueMap );
    	for( Object obj: context.getKeys() ){
    		log.debug( obj + " = " + context.get( (String) obj ) );
    	}
    	log.debug( "using template: " + template );
    	ve.evaluate( context, output, tagForLogMessages, reader );
    	log.debug( "generated output: \n" + output.toString() );
    	return output.toString();
    }
}
